import cn.hutool.core.util.StrUtil;

import java.nio.charset.Charset;

/**
 * @author weipt
 * @description
 * @date 2024/4/24 22:47
 */
public class GBKStringTruncator {
    public static void main(String[] args) {
        String originalString = "123232好1我们1212这是一个包含中文和英文的字符串";
        int byteLimit = 12; // 假设我们想限制字符串的字节长度不超过20
        String truncatedString = truncateGBKString(originalString, byteLimit, "GBK");
        System.out.println("原始字符串: " + originalString);
        System.out.println("截取后的字符串: " + truncatedString);
    }

    public static String truncateGBKString(String str, int byteLimit, String charSetName)  throws IllegalArgumentException{
        int cnCharNum;
        if("UTF-8".equalsIgnoreCase(charSetName) || "UTF8".equalsIgnoreCase(charSetName)){
            cnCharNum = 3;
        }else if("GBK".equalsIgnoreCase(charSetName) || "GB2312".equalsIgnoreCase(charSetName) || "GB18030".equalsIgnoreCase(charSetName)){
            cnCharNum = 2;
        }else{
            throw new IllegalArgumentException("Unsupported character set: " + charSetName);
        }
        if (StrUtil.isEmpty(str)) {
            return str;
        }

        // 确保byteLimit是正数
        if (byteLimit <= 0) {
            throw new IllegalArgumentException("Byte limit must be greater than 0");
        }

        // 检查原始字符串的字节长度是否已经小于等于限制
        byte[] bytes = str.getBytes(Charset.forName(charSetName));
        if (bytes.length <= byteLimit) {
            return str;
        }
        int safeNum = 0;
        // 从末尾开始检查，找到最后一个完整的字符（确保不截断中文字符）
        for (int i =0 ;i < bytes.length; i++) {
            if ((bytes[i] & 0x80) == 0) { //判断是否中文，0x80，就是10000000，中文都是1开头
                // 如果不是中文字符的一部分（即英文字符或部分符号）
                safeNum ++;
            }else{
                safeNum = safeNum + cnCharNum;  //如果是utf8就需要加3
                i = i + cnCharNum - 1; //跳过已统计字节
            }
            //相等就跳出，没必要再往后走
            if(safeNum == byteLimit){
                break;
            }
            //大于，说明超过了，我们就需要减去1个
            if(safeNum > byteLimit){
                safeNum = safeNum - cnCharNum;  //如果是utf8就需要减2
                break;
            }
        }
        // 如果整个字符串都是中文字符，则至少保留一个完整的字符
        return new String(bytes, 0, safeNum, Charset.forName(charSetName));
    }
}
